import java.util.Scanner; 
import java.util.Date;
import java.util.Random;

public class WMBSystem{
// ATTRIBUTES **************************************************************************************
   private Scanner sc;
   private Random rand = new Random();
   private ManagerAdvisoryClient mac ;
   private ManagerExecutionClient mec;
   private ManagerFullyManagedClient mfmc;
   private ManagerStock ms;
   private ManagerTypedBroker mtb;
   private ManagerStockDetail msd;
   public AdvisoryClient currentAC;
   public ExecutionClient currentEC;
   public FullyManagedClient currentFMC;
   public int currentType;
   
// CONSTRUCTOR *************************************************************************************
   public WMBSystem() throws ClassNotFoundException
   {
      sc = new Scanner(System.in);
      mac = new ManagerAdvisoryClient();
      //mac.Database();
      mec = new ManagerExecutionClient();
      //mec.Database();
      mfmc = new ManagerFullyManagedClient();
      mfmc.Database();
      ms = new ManagerStock();
      //ms.Database();
      mtb = new ManagerTypedBroker();
      msd = new ManagerStockDetail();
      autoSend();
   }  
   
   private void autoSend()
   {
      int length = mac.length;
      int i;
      TypedBroker tb1;
      TypedBroker tb2;
      for (i = 0; i < length; i++)
      {
         tb1 = new TypedBroker(rand.nextInt(), "MKS", mac.lstObject.get(i).getId(), true, 2);
         tb2 = new TypedBroker(rand.nextInt(), "LLOY", mac.lstObject.get(i).getId(), false, 1);
         mtb.AddToList(tb1);
         mtb.AddToList(tb2);                           
      }
      length = mfmc.length;
      for (i = 0; i < length; i++)
      {
         tb1 = new TypedBroker(rand.nextInt(), "MKS", mfmc.lstObject.get(i).getId(), true, 2);
         tb2 = new TypedBroker(rand.nextInt(), "LLOY", mfmc.lstObject.get(i).getId(), false, 1);   
         mtb.AddToList(tb1);
         mtb.AddToList(tb2);     
      }
      mtb.SaveDataToFile();
   }
    
// METHODS *****************************************************************************************  
   public void mainMenu()
   {            
      System.out.println("--------------------");
      System.out.println("1 - Sign in");
      System.out.println("2 - Registry");
      System.out.println("3 - Exit");
      System.out.println("Enter your choice: ");
      int choice = sc.nextInt();
      sc.nextLine();
      while(choice < 1 || choice > 3)//validate to return a valid option only
		{
			System.out.println("Option out of range, enter again ... ");
         System.out.println("Enter your choice: ");         
			choice = sc.nextInt();//asks for user input until valid input is inserted
		}

      switch(choice)
      {
         case 1:
            signIn();
            break;
         case 2:
            registry();
            break;
         default:
            System.out.println("Thanks! See you later!");
            break;            
      }
   }
   
   private void registry()
   {
      String username;
      String password;
      String email;
      float cash;
      int type;
      float fca;
      
      System.out.println("--------------------");
      System.out.println("\nCREATE ACCOUNT\n");
      System.out.println("Username: ");

      username = sc.nextLine();
      System.out.println("Password: ");
      password = sc.nextLine();
      System.out.println("Email: ");
      email = sc.nextLine();
      System.out.println("Cash: ");
      cash = sc.nextFloat();
      System.out.println("Type (1 - Execution | 2 - Advisory | 3 - Fully managed): ");
      type = sc.nextInt();
      switch (type)
      {
         case 1:
            currentEC = new ExecutionClient(rand.nextInt(), username, password, email, cash);
            currentType = 1;
            mec.AddToList(currentEC);
            mec.SaveDataToFile();
            executionClientMenu();
            break;
         case 2:
            currentAC = new AdvisoryClient(rand.nextInt(), username, password, email, cash);
            currentType = 2;
            mac.AddToList(currentAC);
            mac.SaveDataToFile();
            advisoryClientMenu();
            break;
         case 3:
            System.out.println("FCA: ");
            fca = sc.nextFloat();
            currentFMC = new FullyManagedClient(rand.nextInt(), username, password, email, cash, fca);
            currentType = 3;
            mfmc.AddToList(currentFMC);
            mfmc.SaveDataToFile();
            fullyManagedClientMenu();
            break;
         default:
            break;
      }
   }

   private void signIn()
   {
      String username;
      String password;
      
      System.out.println("--------------------");
      System.out.println("\nLOG IN\n");
      System.out.flush();
      System.out.println("Username: ");

      username = sc.nextLine();
      System.out.println("Password: ");
      password = sc.nextLine();
      
      currentEC = mec.SignIn(username, password);
      if (currentEC != null)
      {
         currentType = 1;
         executionClientMenu();
      }
      else
      {
         currentAC = mac.SignIn(username, password);
         if (currentAC != null)
         {
            currentType = 2;
            advisoryClientMenu();
         }
         else
         {
            currentFMC = mfmc.SignIn(username, password);
            if (currentFMC != null)
            {
               currentType = 3;
               fullyManagedClientMenu();
            }
            else
            {
               System.out.println("Your username or password is invalid!");
               mainMenu();
            }
         }
      }
   }
   
   // Execution Client *****************************************************************************
   private void executionClientMenu()
   {
      System.out.println("--------------------");
      System.out.println("\nMENU\n");
      System.out.println("1 - My Profile ");
      System.out.println("2 - Change password ");
      System.out.println("3 - Change email ");
      System.out.println("4 - Deposit or withdraw cash ");
      System.out.println("5 - Buy and Sell shares ");
      System.out.println("6 - Sign out ");
      System.out.println("Enter your choice: ");
      int choice = sc.nextInt();
      sc.nextLine();
      while(choice < 1 || choice > 6)//validate to return a valid option only
		{
			System.out.println("Option out of range, enter again ... ");
         System.out.println("Enter your choice: ");         
			choice = sc.nextInt();//asks for user input until valid input is inserted
		}

      switch(choice)
      {
         case 1:
            myProfile();
            break;
         case 2:
            changePassword();
            break;
         case 3:
            changeEmail();
            break;
         case 4:
            DepositOrWithdrawCash();
            break;
         case 5:
            BuyAndSellShares();
            break;
         default:
            signOut();
            break;            
      }
   }
   
   // Advisory Client *****************************************************************************
   private void advisoryClientMenu()
   {
      System.out.println("--------------------");
      System.out.println("\nMENU\n");
      System.out.println("1 - My Profile ");
      System.out.println("2 - Change password ");
      System.out.println("3 - Change email ");
      System.out.println("4 - Deposit or withdraw cash ");
      System.out.println("5 - Buy and Sell shares ");
      System.out.println("6 - Show messages from Broker ");
      System.out.println("7 - Sign out ");
      System.out.println("Enter your choice: ");
      int choice = sc.nextInt();
      sc.nextLine();
      while(choice < 1 || choice > 7)//validate to return a valid option only
		{
			System.out.println("Option out of range, enter again ... ");
         System.out.println("Enter your choice: ");         
			choice = sc.nextInt();//asks for user input until valid input is inserted
		}

      switch(choice)
      {
         case 1:
            myProfile();
            break;
         case 2:
            changePassword();
            break;
         case 3:
            changeEmail();
            break;
         case 4:
            DepositOrWithdrawCash();
            break;
         case 5:
            BuyAndSellShares();
            break;
         case 6:
            ShowMessage();
         default:
            signOut();
            break;            
      }
   }
   
   private void ShowMessage()
   {
      String choice = "";
      switch(currentType)
      {
         case 2:
            mtb.ShowMessage(currentAC.getId());
            System.out.println("Press any key to back ");
            choice = sc.nextLine();
            advisoryClientMenu();
            break;
         case 3:
            mtb.ShowMessage(currentFMC.getId());
            System.out.println("Press any key to back ");
            choice = sc.nextLine();
            fullyManagedClientMenu();
            break;
         default:
            System.out.println("ERROR");
            mainMenu();
      }
   }

   // Fully managed Client *************************************************************************
   private void fullyManagedClientMenu()
   {
      System.out.println("--------------------");
      System.out.println("\nMENU\n");
      System.out.println("1 - My Profile ");
      System.out.println("2 - Change password ");
      System.out.println("3 - Change email ");
      System.out.println("4 - Change FCA ");
      System.out.println("5 - Deposit or withdraw cash ");
      System.out.println("6 - Buy and Sell shares ");
      System.out.println("7 - Show messages from Broker ");
      System.out.println("8 - Sign out ");
      System.out.println("Enter your choice: ");
      int choice = sc.nextInt();
      sc.nextLine();
      while(choice < 1 || choice > 8)//validate to return a valid option only
		{
			System.out.println("Option out of range, enter again ... ");
         System.out.println("Enter your choice: ");         
			choice = sc.nextInt();//asks for user input until valid input is inserted
		}

      switch(choice)
      {
         case 1:
            myProfile();
            break;
         case 2:
            changePassword();
            break;
         case 3:
            changeEmail();
            break;
         case 4:
            changeFCA();
         case 5:
            DepositOrWithdrawCash();
            break;
         case 6:
            BuyAndSellShares();
            break;
         case 7:
            ShowMessage();
            break;
         default:
            signOut();
            break;            
      }
   }
   
   private void changeFCA()
   {
      System.out.println("--------------------");
      System.out.println("\nCHANGE FCA\n");
      System.out.println("Enter new FCA: ");
      float fca = sc.nextFloat();
      if (mfmc.ChangeFCA(currentFMC, fca))
      {
         currentFMC.setFCA(fca);
         System.out.println("Change FCA is successful!");
         fullyManagedClientMenu();
      }
      else
      {
         System.out.println("Change FCA is fail!");
         fullyManagedClientMenu();
      }
   }

   // **********************************************************************************************
   private void myProfile()
   {
      String name, password, email;
      float cash;
      
      switch(currentType)
      {
         case 1:
            name = currentEC.getName();
            password = currentEC.getPassword();
            email = currentEC.getEmail();
            cash = currentEC.getCash();
            break;
         case 2:
            name = currentAC.getName();
            password = currentAC.getPassword();
            email = currentAC.getEmail();
            cash = currentAC.getCash();
            break;
         case 3:
            name = currentFMC.getName();
            password = currentFMC.getPassword();
            email = currentFMC.getEmail();
            cash = currentFMC.getCash();
            break;
         default: 
            name = "";
            password = "";
            email = "";
            cash = 0;
            System.out.println("ERROR!"); 
            mainMenu();  
      }

      System.out.println("--------------------");
      System.out.println("\nMY PROFILE\n");
      System.out.println(String.format("Name: %s", name));
      System.out.println(String.format("Password: %s", password));
      System.out.println(String.format("Email: %s", email));
      System.out.println(String.format("Cash: %f", cash));
      System.out.println("Press any key to back ");
      String choice = sc.nextLine();
      switch(currentType)
      {
         case 1:
            executionClientMenu();
            break;
         case 2:
            advisoryClientMenu();
            break;
         case 3:
            fullyManagedClientMenu();
            break;
         default: 
            System.out.println("ERROR!"); 
            mainMenu();  
      }
   }

   private void changePassword()
   {
      String oldPassword = "";
      String newPassword = "";
      String confirmPassword = "";
      System.out.println("--------------------");
      System.out.println("\nCHANGE PASSWORD\n");
      System.out.println("Old password: ");
      oldPassword = sc.nextLine();
      System.out.println("New password: ");
      newPassword = sc.nextLine();
      System.out.println("Confirm password: ");
      confirmPassword = sc.nextLine();
      
      switch(currentType)
      {
         case 1:
            if (mec.ChangePassword(currentEC, oldPassword, newPassword, confirmPassword))
            {
               currentEC.setPassword(newPassword);
               System.out.println("Change password is succesful!");
            }
            else
            {
               System.out.println("Your password is invalid!");
               executionClientMenu();
            }
            break;
         case 2:
            if (mac.ChangePassword(currentAC, oldPassword, newPassword, confirmPassword))
            {
               currentAC.setPassword(newPassword);
               System.out.println("Change password is succesful!");
            }
            else
            {
               System.out.println("Your password is invalid!");
               advisoryClientMenu();
            }
            break;
         case 3:
            if (mfmc.ChangePassword(currentFMC, oldPassword, newPassword, confirmPassword))
            {
               currentFMC.setPassword(newPassword);
               System.out.println("Change password is succesful!");
            }
            else
            {
               System.out.println("Your password is invalid!");
               fullyManagedClientMenu();
            }
            break;
      }
      System.out.println("Press any key to back ");
      String choice = sc.nextLine();
      switch(currentType)
      {
         case 1:
            executionClientMenu();
            break;
         case 2:
            advisoryClientMenu();
            break;
         case 3:
            fullyManagedClientMenu();
            break;
         default: 
            System.out.println("ERROR!"); 
            mainMenu();  
      }
   }
   
   private void changeEmail()
   {
      String newEmail = "";
      System.out.println("--------------------");
      System.out.println("\nCHANGE EMAIL\n");
      System.out.println("New Email: ");
      newEmail = sc.nextLine();
            
      switch(currentType)
      {
         case 1:
            if (mec.ChangeEmail(currentEC, newEmail))
            {
               currentEC.setEmail(newEmail);
               System.out.println("Change email is succesful!");
            }
            else
            {
               System.out.println("Your email is invalid!");
               executionClientMenu();
            }
            break;
         case 2:
            if (mac.ChangeEmail(currentAC, newEmail))
            {
               currentAC.setEmail(newEmail);
               System.out.println("Change email is succesful!");
            }
            else
            {
               System.out.println("Your email is invalid!");
               advisoryClientMenu();
            }
            break;
         case 3:
            if (mfmc.ChangeEmail(currentFMC, newEmail))
            {
               currentFMC.setEmail(newEmail);
               System.out.println("Change email is succesful!");
            }
            else
            {
               System.out.println("Your email is invalid!");
               fullyManagedClientMenu();
            }
            break;
      }
      System.out.println("Press any key to back ");
      String choice = sc.nextLine();
      switch(currentType)
      {
         case 1:
            executionClientMenu();
            break;
         case 2:
            advisoryClientMenu();
            break;
         case 3:
            fullyManagedClientMenu();
            break;
         default: 
            System.out.println("ERROR!"); 
            mainMenu();  
      }
   }
   
   private void DepositOrWithdrawCash()
   {
      int choice;
      float balance;
      System.out.println("--------------------");
      System.out.println("\nDEPOSIT OR WITHDRAW CASH\n");
      System.out.println("Enter your choice: (1 - Deposit cash ; 2 - Withdraw cash)");
      choice = sc.nextInt();
      while(choice < 1 || choice > 2)//validate to return a valid option only
		{
			System.out.println("Option out of range, enter again ... ");
         System.out.println("Enter your choice: ");         
			choice = sc.nextInt();//asks for user input until valid input is inserted
		}
      System.out.println("Enter your cash balance: ");
      balance = sc.nextFloat();
      while(balance < 1)//validate to return a valid option only
		{
			System.out.println("Option out of range, enter again ... ");
         System.out.println("Enter your choice: ");         
			balance = sc.nextFloat();//asks for user input until valid input is inserted
		}

      switch(currentType)
      {
         case 1:
            if (mec.DepositOrWithdrawCash(currentEC, choice, balance))
            {
               if (choice == 1)
                  currentEC.depositCash(balance);
               else
                  currentEC.withdrawCash(balance);
               System.out.println("Transaction is successful");
            }
            else
            {
               System.out.println("Transaction is fail");
            }
            executionClientMenu();
            break;
         case 2:
            if (mac.DepositOrWithdrawCash(currentAC, choice, balance))
            {
               if (choice == 1)
                  currentAC.depositCash(balance);
               else
                  currentAC.withdrawCash(balance);
               System.out.println("Transaction is successful");
            }
            else
            {
               System.out.println("Transaction is fail");
            }
            advisoryClientMenu();
            break;
         case 3:
            if (mfmc.DepositOrWithdrawCash(currentFMC, choice, balance))
            {
               if (choice == 1)
                  currentFMC.depositCash(balance);
               else
                  currentFMC.withdrawCash(balance);
               System.out.println("Transaction is successful");
            }
            else
            {
               System.out.println("Transaction is fail");
            }
            fullyManagedClientMenu();
            break;
         default: 
            System.out.println("ERROR!"); 
            mainMenu();  
      }

   }
   
   private void BuyAndSellShares()
   {
      int choice;
      
      //float 
      System.out.println("--------------------");
      System.out.println("\nBUY AND SELL SHARES\n");
      ms.ShowInfoOfList();
      System.out.println("Enter your choice (1 - Buy ; 2 - Sell): ");
      choice = sc.nextInt();
      while(choice < 1 || choice > 2)//validate to return a valid option only
		{
			System.out.println("Option out of range, enter again ... ");
         System.out.println("Enter your choice: ");         
			choice = sc.nextInt();//asks for user input until valid input is inserted
		}
      if (choice == 1)
      {         
         BuyShares();        
      }
      else
      {
         SellShares();
      }
   }
   
   private void BuyShares()
   {
      String code;
      int nShares;
      sc.nextLine();
      System.out.println("Enter stock code: ");      
      code = sc.nextLine();         
      Stock stock = ms.GetByCode(code);
      if (stock != null)
      {
         System.out.println("Enter number of shares: ");
         nShares = sc.nextInt();
         StockDetail stockDetail;
         switch(currentType)
         {
            case 1:
               if (mec.BuyShares(currentEC, stock, nShares))
               {
                  stockDetail = new StockDetail(rand.nextInt(), stock.getCode(), currentEC.getId(), new Date(), stock.getPrice(), nShares);
                  msd.AddToList(stockDetail);
                  msd.SaveDataToFile();
                  //currentEC.withdrawCash(nShares*stock.getPrice());
                  System.out.println("Transaction is successful");
               }
               else
               {
                  System.out.println("Transaction is fail");
               }
               executionClientMenu();
               break;
            case 2:
               if (mac.BuyShares(currentAC, stock, nShares))
               {
                  stockDetail = new StockDetail(rand.nextInt(), stock.getCode(), currentAC.getId(), new Date(), stock.getPrice(), nShares);
                  msd.AddToList(stockDetail);
                  msd.SaveDataToFile();
                  //currentAC.withdrawCash(nShares*stock.getPrice());
                  System.out.println("Transaction is successful");
               }
               else
               {
                  System.out.println("Transaction is fail");
               }
               advisoryClientMenu();
               break;
            case 3:
               if (mfmc.BuyShares(currentFMC, stock, nShares))
               {
                  stockDetail = new StockDetail(rand.nextInt(), stock.getCode(), currentFMC.getId(), new Date(), stock.getPrice(), nShares);
                  msd.AddToList(stockDetail);
                  msd.SaveDataToFile();
                  //currentFMC.withdrawCash(nShares*stock.getPrice());
                  System.out.println("Transaction is successful");
               }
               else
               {
                  System.out.println("Transaction is fail");
               }
               fullyManagedClientMenu();
               break;
            default: 
               System.out.println("ERROR!"); 
               mainMenu();  
         }
      }
      else
      {
         System.out.println("This stock is not exist!");
         switch(currentType)
         {
            case 1:
               executionClientMenu();
               break;
            case 2:
               advisoryClientMenu();
               break;
            case 3:
               fullyManagedClientMenu();
               break;
            default: 
               System.out.println("ERROR!"); 
               mainMenu();  
         }      
      }
   }
   
   private void SellShares()
   {
      String code;
      int nShares;
      sc.nextLine();
      System.out.println("Enter stock code: ");      
      code = sc.nextLine();         
      Stock stock = ms.GetByCode(code);
      if (stock != null)
      {
         System.out.println("Enter number of shares: ");
         nShares = sc.nextInt();
         StockDetail stockDetail;
         int count;
         switch(currentType)
         {
            case 1:
               count = 0;
               for (int i = 0; i < msd.lstObject.size(); i++)
               {
                  if (msd.lstObject.get(i).getStockCode().equals(stock.getCode()) && msd.lstObject.get(i).getClientID() == currentEC.getId())
                     count += msd.lstObject.get(i).getNoSharesOwned();
               }
               if (count >= nShares)
               {
                  stockDetail = new StockDetail(rand.nextInt(), stock.getCode(), currentEC.getId(), new Date(), stock.getPrice(), -nShares);
                  msd.AddToList(stockDetail);
                  msd.SaveDataToFile();
                  mec.SellShares(currentEC, stock, nShares);
                  currentEC.depositCash(nShares*stock.getPrice());
                  System.out.println("Transaction is successful");
               }
               else
               {
                  System.out.println("Transaction is fail");
               }
               executionClientMenu();
               break;
            case 2:
               count = 0;
               for (int i = 0; i < msd.lstObject.size(); i++)
               {
                  if (msd.lstObject.get(i).getStockCode().equals(stock.getCode()) && msd.lstObject.get(i).getClientID() == currentAC.getId())
                     count += msd.lstObject.get(i).getNoSharesOwned();
               }
               if (count >= nShares)
               {
                  stockDetail = new StockDetail(rand.nextInt(), stock.getCode(), currentAC.getId(), new Date(), stock.getPrice(), -nShares);
                  msd.AddToList(stockDetail);
                  msd.SaveDataToFile();
                  mac.SellShares(currentAC, stock, nShares);
                  currentAC.depositCash(nShares*stock.getPrice());
                  System.out.println("Transaction is successful");
               }
               else
               {
                  System.out.println("Transaction is fail");
               }
               advisoryClientMenu();
               break;
            case 3:
               count = 0;
               for (int i = 0; i < msd.lstObject.size(); i++)
               {
                  if (msd.lstObject.get(i).getStockCode().equals(stock.getCode()) && msd.lstObject.get(i).getClientID() == currentFMC.getId())
                     count += msd.lstObject.get(i).getNoSharesOwned();
               }
               if (count >= nShares)
               {
                  stockDetail = new StockDetail(rand.nextInt(), stock.getCode(), currentFMC.getId(), new Date(), stock.getPrice(), -nShares);
                  msd.AddToList(stockDetail);
                  msd.SaveDataToFile();
                  mfmc.SellShares(currentFMC, stock, nShares);
                  currentFMC.depositCash(nShares*stock.getPrice());
                  System.out.println("Transaction is successful");
               }
               else
               {
                  System.out.println("Transaction is fail");
               }
               fullyManagedClientMenu();
               break;
            default: 
               System.out.println("ERROR!"); 
               mainMenu();  
         }
      }
      else
      {
         System.out.println("This stock is not exist!");
         switch(currentType)
         {
            case 1:
               executionClientMenu();
               break;
            case 2:
               advisoryClientMenu();
               break;
            case 3:
               fullyManagedClientMenu();
               break;
            default: 
               System.out.println("ERROR!"); 
               mainMenu();  
         }      
      }
   }
   
   private void signOut()
   {
      switch(currentType)
      {
         case 1:
            currentEC = null;            
            break;
         case 2:
            currentAC = null;
            break;
         case 3:
            currentFMC = null;
      }
      currentType = 0;
      mainMenu();
   }
}